package com.dx.oa.activitiManager.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.zip.ZipInputStream;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.dx.oa.activitiManager.service.IWorkFlowService;
import com.dx.oa.framework.util.UserUtils;
import com.github.pagehelper.util.StringUtil;

@Service
public class WorkFlowService implements IWorkFlowService{

	@Autowired
	private RepositoryService repositoryService;
	
	@Autowired
	private RuntimeService runtimeService;
	
	@Autowired
	private TaskService taskService;
	
	@Autowired
	private HistoryService historyService;
	
	@Autowired
	private FormService formService;

	
	public List<Deployment> getDeployments() {
		// TODO Auto-generated method stub
		return repositoryService.createDeploymentQuery().orderByDeploymenTime().desc().list();
	}

	public Deployment addDeployment(MultipartFile file, String deployName) {
		// TODO Auto-generated method stub
		if(file != null)
		{
			try {
				ZipInputStream inputStream = new ZipInputStream(file.getInputStream());
				Deployment deploy  = repositoryService.createDeployment().addZipInputStream(inputStream)
						.name(deployName).deploy();
				System.out.println("流程部署的id:" + deploy.getId());
				System.out.println("流程部署的名称:" + deploy.getName());
				return deploy;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}
		return null;
	}

	public boolean delDeploymentById(String deploymentId,boolean flag) {
		// TODO Auto-generated method stub
		try
		{
			repositoryService.deleteDeployment(deploymentId,flag);
		}
		catch(Exception e)
		{
			return false;
		}
		return true;
	}

	/**
	 * 从这里可以还进行一步操作,当我们在
	 * 实际应用中,查询流程定义的时候
	 * 实际只需要查询最新版本的流程定义信息
	 */
	public List<ProcessDefinition> getProcessDefList() {
		// TODO Auto-generated method stub
		TreeMap<String,ProcessDefinition> mymap = new TreeMap<String,ProcessDefinition>();
		List<ProcessDefinition> pdList = repositoryService.createProcessDefinitionQuery().orderByProcessDefinitionVersion().asc().list();
		for (ProcessDefinition pdf:pdList) {
			mymap.put(pdf.getKey(), pdf);
		}
		pdList.clear();
	    pdList.addAll(mymap.values());
	    return pdList;
	}

	public InputStream getProcessDefImageStream(String deploymentId, String imageName) {
		return repositoryService.getResourceAsStream(deploymentId, imageName);
	}

	public ProcessInstance startProcess(String leaveProcessKey, String businessKey, Map<String, Object> variables) {
 		return runtimeService.startProcessInstanceByKey(leaveProcessKey, businessKey, variables);
	}

	public List<Task> getTaskList(String assignee) {
		// TODO Auto-generated method stub
		if(assignee != null)
			return taskService.createTaskQuery().taskAssignee(assignee).list();
		else
			return taskService.createTaskQuery().list();
	}

	public String getTaskFormKeyByTaskId(String taskId) {
		// TODO Auto-generated method stub
		TaskFormData tfd = formService.getTaskFormData(taskId);
		return tfd.getFormKey();
	}

	public Task getTaskById(String taskId) {
		// TODO Auto-generated method stub
		return taskService.createTaskQuery().taskId(taskId).singleResult();
	}

	public ProcessInstance getProcessInstanceById(String pid) {
		// TODO Auto-generated method stub
		return runtimeService.createProcessInstanceQuery().processInstanceId(pid).singleResult();
	}

	public List<PvmTransition>  getOutComeListByTaskId(String taskId) {
		// TODO Auto-generated method stub
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		String processDefinitionId = task.getProcessDefinitionId();
		String processInstanceId = task.getProcessInstanceId();
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
				.processInstanceId(processInstanceId).singleResult();
		
		String activityId = processInstance.getActivityId();
		
		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processDefinitionId);
		List<PvmTransition>  pvmTransitionList = processDefinitionEntity.findActivity(activityId).getOutgoingTransitions();
		return pvmTransitionList;
	}

	public List<Comment> getCommentListByTaskId(String taskId) {
		// TODO Auto-generated method stub
		//return null;
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		String processInstanceId = task.getProcessInstanceId();
		return taskService.getProcessInstanceComments(processInstanceId);
	}

	/**
	 * 1.根据页面按钮的不同来决定流程走向
	 */
	@Transactional(isolation=Isolation.DEFAULT ,propagation = Propagation.REQUIRED)
	public void completeTask(String taskId, String outcome, String commentMsg) {
		// TODO Auto-generated method stub
		Map<String,Object> variables = new HashMap<String,Object>();
//		System.out.println(outcome);
		if(outcome!= null && !outcome.equals("确认提交"))
		{
			variables.put("outcome", outcome);
		}
		Authentication.setAuthenticatedUserId(UserUtils.getCurrentUserName());
		String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
		if(StringUtil.isNotEmpty(commentMsg))
		{
			taskService.addComment(taskId, processInstanceId, commentMsg);
		}
		//完成任务
		taskService.complete(taskId, variables);
	}

	public String getDeploymentIdByPID(String processInstanceId) {
		// TODO Auto-generated method stub
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		if(processInstance == null)
		{
			//System.out.println("processInstance is null");
			HistoricProcessInstance historyProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			//System.out.println(historyProcessInstance);
			return repositoryService.createProcessDefinitionQuery().processDefinitionId(historyProcessInstance.getProcessDefinitionId()).singleResult().getDeploymentId();
		}
		return processInstance.getDeploymentId();
	}

	public String getImageNameByPId(String processInstanceId) {
		// TODO Auto-generated method stub
		//return runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId);
		return repositoryService.createProcessDefinitionQuery().deploymentId(getDeploymentIdByPID(processInstanceId)).singleResult().getDiagramResourceName();
	}

	public ActivityImpl getActivitiCoordinate(String processInstanceId) {
		// TODO Auto-generated method stub
		ProcessInstance  processInstance = runtimeService.createProcessInstanceQuery()
				.processInstanceId(processInstanceId)
				.singleResult();
		if(processInstance!=null){
			//获取此流程实例当前的活动id
			String activityId = processInstance.getActivityId();			
			//通过流程定义的实现类ProcessDefinitionEntity 来获取当前活动的坐标
			String processDefinitionId = processInstance.getProcessDefinitionId();
			ProcessDefinitionEntity processDefinitionEntity =(ProcessDefinitionEntity)
			repositoryService.getProcessDefinition(processDefinitionId);
			ActivityImpl activityImpl = processDefinitionEntity.findActivity(activityId);	
			return activityImpl;
		}
		else{
			return null;
		}
	}

}
